#include "fifo.h"

z_fifo z_fifo_init(char *p)
{
	z_fifo tmp = {
		p,
		0
	};

	return tmp;
}

int z_fifo_release(z_fifo f)
{
	return 0;
}

char *z_fifo_path_get(z_fifo *f)
{
	return f->path;
}

char *z_fifo_path_set(z_fifo *f, char *p)
{
	return (f->path = p);
}

int z_fifo_filedesc_get(z_fifo *f)
{
	return f->fd;
}

int z_fifo_create(z_fifo *f)
{
	if (mkfifo(f->path, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH) == 0)
		return 0;
	return 1;
}

int z_fifo_connect_read(z_fifo *f)
{
	return (f->fd = open(f->path, O_RDONLY | O_NONBLOCK));
}

int z_fifo_connect_write(z_fifo *f)
{
	return (f->fd = open(f->path, O_WRONLY | O_NONBLOCK));
}

int z_fifo_disconnect(z_fifo *f)
{
	close(f->fd);
	return 0;
}

void *z_fifo_read(z_fifo *f, z_size s)
{
	void *buf = malloc(s);
	if (read(f->fd, buf, s) < 0)
	{
		free(buf);
		return NULL;
	}

	return buf;
}

int z_fifo_write(z_fifo *f, z_size s, void *d)
{
	if (write(f->fd, d, s) < 0)
		return 1;
	return 0;
}

z_ipc z_ipc_init(char *basedir, int id, int me)
{
	z_ipc tmp;
	tmp.me = me;

	char p0[64];
	sprintf(p0, "%s/%i_0", basedir, id);

	char p1[64];
	sprintf(p1, "%s/%i_1", basedir, id);

	tmp.f[0] = z_fifo_init(strdup(p0));
	z_fifo_create(&(tmp.f[0]));

	tmp.f[1] = z_fifo_init(strdup(p1));
	z_fifo_create(&(tmp.f[1]));

	return tmp;
}

int z_ipc_release(z_ipc i)
{
	z_fifo_disconnect(&(i.f[0]));
	z_fifo_disconnect(&(i.f[1]));
	z_fifo_release(i.f[0]);
	z_fifo_release(i.f[1]);
	return 0;
}

int z_ipc_me_get(z_ipc *i)
{
	return i->me;
}

int z_ipc_me_set(z_ipc *i, int m)
{
	return (i->me = m);
}

z_fifo z_ipc_fifo_me(z_ipc *i)
{
	return i->f[i->me];
}

z_fifo z_ipc_fifo_them(z_ipc *i)
{
	return i->f[!i->me];
}

z_data z_ipc_request_data(z_ipc *i, z_data d)
{
	z_fifo tmp = z_ipc_fifo_them(i);
	z_fifo_connect_write(&tmp);
	z_fifo_write(&tmp, sizeof(z_data), &d);
	z_fifo_disconnect(&tmp);
	tmp = z_ipc_fifo_me(i);
	z_fifo_connect_read(&tmp);
	z_data *req = (z_data *)z_fifo_read(&tmp, sizeof(z_data));
	z_fifo_disconnect(&tmp);
	if (req != NULL)
		return *req;
	else
		return z_data_init(0, 0);
}

z_data z_ipc_wait_on_request(z_ipc *i)
{
	z_fifo tmp = z_ipc_fifo_me(i);
	z_fifo_connect_read(&tmp);
	z_data *req = (z_data *)z_fifo_read(&tmp, sizeof(z_data));
	if (req == NULL)
	{
		z_fifo_disconnect(&tmp);
		return z_data_init(0, 0);
	}
	else
	{
		z_data_src_set(req, ((void *)req)+sizeof(z_data));
		z_fifo_disconnect(&tmp);
		return *req;
	}
}

int z_ipc_send_data(z_ipc *i, z_data d)
{
	z_fifo tmp = z_ipc_fifo_them(i);
	void *buf = malloc(sizeof(z_data)+z_data_size_get(&d));
	memcpy(buf, &d, sizeof(z_data));
	memcpy(buf+sizeof(z_data), z_data_src_get(&d), z_data_size_get(&d));
	z_fifo_connect_write(&tmp);
	int e = z_fifo_write(&tmp, sizeof(z_data)+z_data_size_get(&d), buf);
	z_fifo_disconnect(&tmp);
	return e;
}

